# 获取各个音乐网站的音乐资源
import requests, base64, time, random, codecs, json
from fake_useragent import UserAgent
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad as ppad


class BaseMusic:
    name = None
    ua = UserAgent()

    def __init__(self):
        assert self.name is not None, "name 属性必须为true"
        self.session = requests.Session()
        self.session.headers = {
            "Referer": "https://music.163.com/",
            "User-Agent": self.ua.random
        }

    def get_Songs(self, songId: int):
        '''
        :param song_name: 歌曲的名字
        :return: 歌曲的mp3地址
        '''
        assert Exception("必须实现get_Songs方法")

    def search_KeyWord(self, keyword: str, offset: int):
        '''
        :param keyword: 关键字
        :param type: 类型：单曲，专辑，歌词，用户，视频
        :return: json格式数据
        '''
        assert Exception("必须实现search_KeyWord方法")


class WYYMusic(BaseMusic):
    name = "网易云"

    SearchKeyWord = '{"hlpretag":" <span class =\\\"s-fc7\\\">", "hlposttag":"</span>", "s": "%s", "type": "1", "offset": "%s", "total": "true", "limit": "30", "csrf_token": ""}'
    Comments = '{"rid":"R_SO_4_%s","offset":"%s","total":"true","limit":"20","csrf_token":""}'
    SongUrl = '{"ids":"[%s]","level":"standard","encodeType":"aac","csrf_token":""}'

    def __init__(self):
        self.arg2 = "010001"
        self.arg3 = "00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3ab17a876aea8a5aa76d2e417629ec4ee341f56135fccf695280104e0312ecbda92557c93870114af6c9d05c4f7f0c3685b7a46bee255932575cce10b424d813cfe4875d3e82047b97ddef52741d546b8e289dc6935b3ece0462db0a22b8e7"
        self.arg4 = "0CoJUm6Qyw8W8jud"
        self.__get_random_str()
        super().__init__()

    def __AES_encrypt(self, text, key) -> str:
        '''
        获取到加密后的数据
        :param text: 首先CBC加密方法，text必须位16位数据
        :param key: 加密的key
        :return: 加密后的字符串
        '''
        iv = "0102030405060708"
        pad = 16 - len(text) % 16
        if isinstance(text, str):
            text = text + pad * chr(pad)
        else:
            text = str(text, encoding="utf-8") + pad * chr(pad)
        aes = AES.new(key=bytes(key, encoding="utf-8"), mode=2, iv=bytes(iv, encoding="utf-8"))
        res = aes.encrypt(bytes(text, encoding="utf-8"))
        res = base64.b64encode(res).decode("utf-8")
        return res

    def __get_encText(self, args1) -> str:
        encText = self.__AES_encrypt(args1, self.arg4)
        encText = self.__AES_encrypt(encText, self.random_16_str)
        return encText

    def __get_encSecKey(self) -> str:
        '''通过查看js代码，获取encSecKey'''
        text = self.random_16_str[::-1]
        rs = int(codecs.encode(text.encode('utf-8'), 'hex_codec'), 16) ** int(self.arg2, 16) % int(self.arg3, 16)
        return format(rs, 'x').zfill(256)

    def __get_random_str(self):
        '''这是16位的随机字符串'''
        str_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
        random_str = ""
        for i in range(16):
            index = random.randint(0, len(str_set) - 1)
            random_str += str_set[index]
        self.random_16_str = "sGHiNtvVInv7CR8B"

    def __getFormData(self, args1) -> dict:
        '''获取到提交的数据'''
        data = {"params": self.__get_encText(args1), "encSecKey": self.__get_encSecKey()}
        return data

    def __timestamp_to_timeformate(self, timestamp) -> str:
        '''将时间戳转为某种格式的时间'''
        time_local = time.localtime(timestamp / 1000)
        dt = time.strftime("%Y-%m-%d %H:%M:%S", time_local)
        return dt

    def get_Songs(self, songId: int) -> str:
        arg_mp3 = self.SongUrl % songId
        api = "https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token="
        headers = self.session.headers.copy()
        formdata = self.__getFormData(arg_mp3)
        response = self.session.post(url=api, data=formdata, headers=headers)
        mp3Url = response.json()["data"][0]["url"]
        return mp3Url

    def search_KeyWord(self, kw: str, offset: int = 0) -> dict:
        json_dict = {}
        song_list = []

        arg_keyword = self.SearchKeyWord % (kw, offset)
        api = "https://music.163.com/weapi/cloudsearch/get/web?csrf_token="
        headers = self.session.headers.copy()
        formdata = self.__getFormData(bytes(arg_keyword, encoding="utf-8"))
        response = self.session.post(url=api, data=formdata, headers=headers).json()
        if response.get("code") != 200:
            return {}
        result = response.get("result")

        # 歌曲Count
        songCount = result.get("songCount", 0)
        songs = result.get("songs", [])
        # 从songs中去除多余的数据
        # 就需要歌曲名字，歌曲演唱者，专辑，歌曲id
        json_dict["count"] = songCount
        for song in songs:
            song_dict = {}
            song_dict["song_name"] = song["name"]
            song_dict["song_id"] = song["id"]
            song_dict["album_name"] = song["al"]["name"]
            song_dict["song_singer"] = [ar["name"] for ar in song["ar"]]
            song_list.append(song_dict)

        json_dict["song_data"] = song_list
        # print(json_dict)
        return json_dict

    def song_comment(self, songId, offset=0) -> list:
        '''获取到歌曲评论信息，我只是将结果print出来，如果保存的话，可以单独写一个保存的方法'''
        results = []
        api = "https://music.163.com/weapi/v1/resource/comments/R_SO_4_{}?csrf_token=".format(songId)
        headers = self.session.headers.copy()
        arg_comment = self.Comments % (songId, offset)
        formdata = self.__getFormData(arg_comment)
        response = self.session.post(url=api, headers=headers, data=formdata)
        comment_list = response.json().get("comments")
        if not comment_list:
            return results
        for comment_dict in comment_list:
            dic = {}
            dic["nickname"] = comment_dict["user"]["nickname"]
            dic["time"] = self.__timestamp_to_timeformate(comment_dict.get("time"))
            dic["content"] = comment_dict.get("content")
            results.append(dic)
        print(json.dumps(results))
        return results



if __name__ == '__main__':
    wyy = WYYMusic()
    # wyy.get_Songs(444267215)
    # wyy.search_KeyWord("只因你太美")
    wyy.song_comment(444267215)
